#include <Arduino.h>
#include <USBComposite.h>
#include <EEPROM.h>

USBHID HID;
HIDJoystick Joystick(HID);

#define POTENTIOMETER_PINX PA0
#define POTENTIOMETER_PINY PA1
#define POTENTIOMETER_PINZ PA2


#define BUTTON1_PIN PB0
#define BUTTON2_PIN PB1
#define BUTTON3_PIN PB2
#define BUTTON4_PIN PB3
#define BUTTON5_PIN PB4
#define BUTTON6_PIN PB5
#define BUTTON7_PIN PB6
#define BUTTON8_PIN PB7
#define BUTTON9_PIN PB8
#define BUTTON10_PIN PB9



#define SET_PIN PA11
#define CS_PIN PA12

//限幅平均滤波法
// https://arduino.nxez.com/2016/12/17/arduino-ten-filter-algorithm-program.html
#define CHANNEL_N 1  //最多多少channel通道
#define FILTER_N 2 //采样数 太大会影响反应数据
#define FILTER_DIFF 500 //过滤异常差值 精度12位，最大值4096，故超过10%=40的值算异常值
uint16 filter_buf_channel[CHANNEL_N][FILTER_N];//过滤算法缓存
uint8 analogPin[CHANNEL_N];//模拟pin

#define ee_save 0 //ee地址开头
#define ee_save_flag 0xf00f //ee是否初始化
#define ee_data 10 //ee数据地址开头
uint16 ee_data_addr_min[CHANNEL_N];
uint16 ee_data_addr_max[CHANNEL_N];
uint16 ee_data_channle_min[CHANNEL_N];
uint16 ee_data_channle_max[CHANNEL_N];
#define ZERO_DIFF 5 //零区偏移，防止静止误差


//发送函数，记录上次发送值，只发送变化值
#define KEY_NUM 20  //多少个按键或者ADC，
uint16 key_buf[KEY_NUM]; //记录按键或者adc的上次值

uint16 MagicNum=0xf0f0;

uint16 flashEECount=0;

// 限幅平均滤波法
uint16 Filter(int channelNo, uint16 adcValue)
{
  int i;
  uint16 filter_sum = 0;
  //读取最小值
  filter_buf_channel[channelNo][FILTER_N - 1] = adcValue;
  //判断是否异常值
  if (
    ((filter_buf_channel[channelNo][FILTER_N - 1] - filter_buf_channel[channelNo][FILTER_N - 2]) > FILTER_DIFF) 
    || ((filter_buf_channel[channelNo][FILTER_N - 2] - filter_buf_channel[channelNo][FILTER_N - 1]) > FILTER_DIFF)
    ){
    filter_buf_channel[channelNo][FILTER_N - 1] = filter_buf_channel[channelNo][FILTER_N - 2];
    }
    //取平均值
  for (i = 0; i < FILTER_N - 1; i++)
  {
    filter_buf_channel[channelNo][i] = filter_buf_channel[channelNo][i + 1];
    filter_sum += filter_buf_channel[channelNo][i];
  }

  return (uint16)filter_sum / (FILTER_N - 1);
}


void sendValue(char type,int keyOrAdc, uint16 value){
   uint16 valueLast=key_buf[keyOrAdc];
   if(valueLast!=value){
    //TODO send MagicNum type keyOrAdc value
    key_buf[keyOrAdc]=value;
   }
}

void initSendValue(uint16 value){
  int i;
    for (i = 0; i < KEY_NUM - 1; i++)
  {
    key_buf[i]=value;
  }
}

uint16 reValue(uint16 rawVaule,uint16 minValue,uint16 maxValue,uint16 rate){
  if(rawVaule<=(minValue+ZERO_DIFF)){
    return 0;
  }
  if(rawVaule>=maxValue){
    return rate;
  }
  float zi=rawVaule-minValue;
  float wu=maxValue-minValue;
  float ret=zi/wu*rate;
  uint16 temp=ret;
  return temp;
}



void setup()
{
  HID.begin(HID_JOYSTICK);
  while (!USBComposite)
    ;

//模拟输入
  pinMode(POTENTIOMETER_PINX, INPUT_ANALOG);
  pinMode(POTENTIOMETER_PINY, INPUT_ANALOG);
  pinMode(POTENTIOMETER_PINZ, INPUT_ANALOG);

 //开关按钮使用,上拉（不用接电阻）
 pinMode(BUTTON1_PIN, INPUT_PULLUP);
//按键使用
  // pinMode(BUTTON1_PIN, INPUT_PULLDOWN);
  // pinMode(BUTTON2_PIN, INPUT_PULLDOWN);


  //无线串口使用
  pinMode(SET_PIN, OUTPUT);
  pinMode(CS_PIN, OUTPUT);

  digitalWrite(SET_PIN, HIGH);
  digitalWrite(CS_PIN, LOW);

  // Serial.begin(115200);
  // Serial.println("joystick start");

  // Serial.begin(115200);
  // HardwareSerial Serial2(USART2);
  // HardwareSerial Serial3(USART3);

  // HardwareSerial Serial1(PA10, PA9);

  // Serial1.begin(9600); // TX=PA9,RX=PA10
  // done 电位器设置正确
  // todo 串口不行，可以代码没有配置正确或者模块问题
  // Serial.println("joystick start");
  // Serial2.begin(115200);  //TX=PA2,RX=PA3
  // Serial3.begin(115200);  //TX=PB10,RX=PB11
  // delay(100);

  //因无线不能做多个设备，只能方向盘hub无线，其他必需有线

  //初始化地址
  for (size_t i = 0; i < CHANNEL_N; i++)
  {
    ee_data_addr_min[i]=ee_data+i;
    ee_data_addr_max[i]=ee_data+20+i;
  }
  analogPin[0]=POTENTIOMETER_PINX;
  analogPin[1]=POTENTIOMETER_PINY;
  analogPin[2]=POTENTIOMETER_PINZ;

  Joystick.Xrotate(0);
  Joystick.Yrotate(0);
  Joystick.slider(0);

   uint16 ee_use_value=EEPROM.read(ee_save);
  //判断是否初始化，及初始化eerom
  if(ee_save_flag!=ee_use_value){
    for (size_t i = 0; i < 500; i++)
    {
      EEPROM.write(i, 0);
    }
    EEPROM.write(ee_save, ee_save_flag);
  }


   //开机按下设置按钮直接读取当前值
  if(digitalRead(BUTTON1_PIN) == LOW){
    for (size_t i = 0; i < CHANNEL_N; i++)
    {
      //读取模拟量
      float newFloat = analogRead(analogPin[i]) / 4 ;
      uint16 valValue=(uint16)newFloat;
      //设置当前值
      ee_data_channle_max[i]=valValue;
      EEPROM.write(ee_data_addr_max[i],valValue);

      ee_data_channle_min[i]=valValue;
      EEPROM.write(ee_data_addr_min[i],valValue);
    }
  }


  //只需要开机读取一次ee值，后面变化会保存ee及有全局变量
  for (size_t i = 0; i < CHANNEL_N; i++)
  {
    uint16 all_value=EEPROM.read(ee_data_addr_min[i]);
    ee_data_channle_min[i]=all_value;

    uint16 all_value_max=EEPROM.read(ee_data_addr_max[i]);
    ee_data_channle_max[i]=all_value_max;
  }
  
}

void loop()
{

 
 

  //按下设置按钮，读取最大值，最小值，eeprom
  if(digitalRead(BUTTON1_PIN) == LOW){

    

    for (size_t i = 0; i < CHANNEL_N; i++)
    {
      //读取ee的值
      uint16 ee_value=EEPROM.read(ee_data_addr_max[i]);
      //读取模拟量
      float newFloat = analogRead(analogPin[i]) / 4 ;
      uint16 valValue=(uint16)newFloat;
      //判断大小值,及保存
      if(valValue>ee_value){
        ee_value=valValue;
        ee_data_channle_max[i]=ee_value;
        EEPROM.write(ee_data_addr_max[i],ee_value);
      }
    }
    for (size_t i = 0; i < CHANNEL_N; i++)
    {
      //读取ee的值
      uint16 ee_value=EEPROM.read(ee_data_addr_min[i]);
      //读取模拟量
      float newFloat = analogRead(analogPin[i]) / 4 ;
      uint16 newValue=(uint16)newFloat;
      //判断大小值,及保存
      if(newValue<ee_value){
        ee_value=newValue;
        ee_data_channle_min[i]=ee_value;
        EEPROM.write(ee_data_addr_min[i],ee_value);
      }
    }

     
   
    
    //设置模式，显示最小值
    if(CHANNEL_N>=1){
      Joystick.Xrotate(reValue(ee_data_channle_min[0],0,1024,1024));
    }
    if(CHANNEL_N>=2){
    Joystick.Yrotate(reValue(ee_data_channle_min[1],0,1024,1024));
    }
    if(CHANNEL_N>=3){
    
    Joystick.slider(reValue(ee_data_channle_min[2],0,1024,1024));
    }
    
    delay (3000) ;


    
    //设置模式，显示最大值
    if(CHANNEL_N>=1){
    Joystick.Xrotate(reValue(ee_data_channle_max[0],0,1024,1024));
    }
    if(CHANNEL_N>=2){
     
    Joystick.Yrotate(reValue(ee_data_channle_max[1],0,1024,1024));
    }
     if(CHANNEL_N>=3){
     
    Joystick.slider(reValue(ee_data_channle_max[2],0,1024,1024));
     }
    delay (6000) ;


    
    //设置模式，显示原始值
     if(CHANNEL_N>=1){
     float valx = analogRead(POTENTIOMETER_PINX) / 4 ; // 0–4095
    Joystick.Xrotate(reValue((uint16)valx,0,1024,1024));
    }
    if(CHANNEL_N>=2){
    
    float valy = analogRead(POTENTIOMETER_PINY) / 4 ; // 0–4095
    Joystick.Yrotate(reValue((uint16)valy,0,1024,1024));
     }
     if(CHANNEL_N>=3){
     
    float valz = analogRead(POTENTIOMETER_PINZ) / 4 ; // 0–4095
    Joystick.slider(reValue((uint16)valz,0,1024,1024));
     }
    delay (9000) ;




  }else{
    //改变比例模式
     if(CHANNEL_N>=1){
    float valx = analogRead(POTENTIOMETER_PINX) / 4 ; // 0–4095
    // Joystick.X(Filter(0,(uint16)valx));
    Joystick.Xrotate(reValue(Filter(0,(uint16)valx),ee_data_channle_min[0],ee_data_channle_max[0],1024));
    }
    if(CHANNEL_N>=2){
    float valy = analogRead(POTENTIOMETER_PINY) / 4 ; // 0–4095
    Joystick.Yrotate(reValue(Filter(1,(uint16)valy),ee_data_channle_min[1],ee_data_channle_max[1],1024));
    }
     if(CHANNEL_N>=3){
    float valz = analogRead(POTENTIOMETER_PINZ) / 4 ; // 0–4095
    Joystick.slider(reValue(Filter(2,(uint16)valz),ee_data_channle_min[2],ee_data_channle_max[2],1024));
    }

  }

 

  // Serial1.print(-1);
  // Serial1.print(-1);
  // Serial1.print(val / 100);
  // int m = fmod(val, 100);
  // Serial1.print(m);

  // Joystick.button(1, digitalRead(BUTTON1_PIN) == HIGH);
  // Joystick.button(2, digitalRead(BUTTON2_PIN) == HIGH);

  //间隔0.001秒发送一次全量数据

    //原代码
    // float valx = analogRead(POTENTIOMETER_PINX) / 4 / 0.7f; // 0–4095
    // // Joystick.X(Filter(0,(uint16)valx));
    // Joystick.Xrotate(Filter(0,(uint16)valx));

    // float valy = analogRead(POTENTIOMETER_PINY) / 4 / 0.7f; // 0–4095
    // Joystick.Yrotate(Filter(1,(uint16)valy));

    // float valz = analogRead(POTENTIOMETER_PINZ) / 4 / 0.7f; // 0–4095
    // Joystick.slider(Filter(2,(uint16)valz));
 

}

